#include "cell.h"

#include "PS3Video.h"
#include "PS3Audio.h"
#include "gambatte_help.h"

#include <sstream>

template <class T>
inline std::string to_string (const T& t)
{
	std::stringstream ss;
	ss << t;
	return ss.str();
}

volatile bool				WantToDie						();

namespace
{
	Setting		SettingDef[] = 
	{
		Setting("Save State Slot      ", " 0\0 1\0 2\0 3\0 4\0 5\0 6\0 7\0 8\0 9\0", 0),
		Setting("Scaler               ", "None*\0Catrom2x\0Catrom3x\0Kreed 2xSaI\0MaxSt Hq2x\0MaxSt Hq3x\0", 0),
		Setting("Vsync                ", "No*\0Yes\0", 0),
		Setting("Underscan            ", " 0%*\0 5%\0 10%\0 15%\0 20%\0 25%\0 30%\0 35%\0 40%\0 45%\0 50%\0", 0),
		Setting("Texture Filter       ", "Off*\0On\0", 0)
	};
	
	enum SettingID {STATE_SLOT, SCALER, VSYNC, UNDERSCAN, TEXTURE_FILTER, SETTING_COUNT};
}

							gbblitter::gbblitter			(GambatteEmu* aEmu)
{
	emulator = aEmu;

	Buffer = 0;
	
	setBufferDimensions(128,128);
	messagetime = 0;
}

							gbblitter::~gbblitter			()
{
	if(Buffer)
	{
		delete Buffer;
	}
}

void						gbblitter::setBufferDimensions	(unsigned aWidth, unsigned aHeight)
{
	if(Buffer)
	{
		delete Buffer;
	}

	Buffer = new FrameBuffer(aWidth, aHeight);

	buffer.pixels = Buffer->GetPixels();
	buffer.pitch = aWidth;
}

const PixelBuffer			gbblitter::inBuffer				()
{
	return buffer;
}

void						gbblitter::blit					()
{
	if(sys_time_get_system_time() - messagetime < 5000 * 1000)
	{
		Buffer->PutString(message.c_str(), 1, 1, 0xFF00FFFF);
	}

	Buffer->SetUnderScan(SettingDef[UNDERSCAN].GetSelected() * 5);
	Buffer->SetFilter(SettingDef[TEXTURE_FILTER].GetSelected());
	Buffer->SetVsync(SettingDef[VSYNC].GetSelected());
	
	if(emulator->ShouldDraw())
	{
		ps3_video->ShowFrame(Buffer);
	}
}

void						gbblitter::ShowMessage			(std::string aMessage)
{
	message = aMessage;
	messagetime = sys_time_get_system_time();
}


							GambatteEmu::GambatteEmu		()
{
	gambatte = new GB();
	blitter = new gbblitter(this);
	input = new gbinput();
	resampler = ResamplerInfo::get(0).create(2097152, 48000, 35112);
	
	SettingsMenu = new SettingMenu(SettingDef, SETTING_COUNT);
	SettingsMenu->ReadFile("/dev_hdd0/game/GMBT90000/USRDIR/config.bin", 0x00000001);
	
	gambatte->set_savedir("/dev_hdd0/game/GMBT90000/USRDIR/save");
	
	sampleoverflow = 0;
	memset(samples, 0, sizeof(samples));
	memset(resamples, 0, sizeof(resamples));
}

							GambatteEmu::~GambatteEmu		()
{
	SettingsMenu->WriteFile("/dev_hdd0/game/GMBT90000/USRDIR/config.bin", 0x00000001);

	delete SettingsMenu;

	delete resampler;
	delete input;
	delete blitter;
	delete gambatte;
}
							
void						GambatteEmu::LoadGame			(std::string aFileName)
{
	gambatte->load(aFileName.c_str(), false);
	gambatte->setVideoBlitter(blitter);
	gambatte->setInputStateGetter(input);
	gambatte->setVideoFilter(SettingDef[SCALER].GetSelected());
	gambatte->selectState(SettingDef[STATE_SLOT].GetSelected());	
}

void						GambatteEmu::Frame				()
{
	Counter.Tick();
	

	ps3_input->Refresh();
	input->inputs.startButton = ps3_input->ButtonPressed(0, PS3_BUTTON_START);
	input->inputs.selectButton = ps3_input->ButtonPressed(0, PS3_BUTTON_SELECT);
	input->inputs.bButton = ps3_input->ButtonPressed(0, PS3_BUTTON_SQUARE);
	input->inputs.aButton = ps3_input->ButtonPressed(0, PS3_BUTTON_CROSS);
	input->inputs.dpadUp = ps3_input->ButtonPressed(0, PS3_BUTTON_UP);
	input->inputs.dpadDown = ps3_input->ButtonPressed(0, PS3_BUTTON_DOWN);
	input->inputs.dpadLeft = ps3_input->ButtonPressed(0, PS3_BUTTON_LEFT);
	input->inputs.dpadRight = ps3_input->ButtonPressed(0, PS3_BUTTON_RIGHT);				

	uint32_t samps = gambatte->runFor((Gambatte::uint_least32_t*)samples, 35112 - sampleoverflow);
	sampleoverflow += samps;
	sampleoverflow -= 35112;
	uint32_t count = resampler->resample((short*)resamples, (short*)samples, samps);
	
	if(Counter.DrawNow())
	{
		ps3_audio->AddSamples(resamples, count);
	}
	
	if(ps3_input->ButtonDown(0, PS3_BUTTON_R3))
	{
		SettingsMenu->DoSettings();
		gambatte->setVideoFilter(SettingDef[SCALER].GetSelected());
		gambatte->selectState(SettingDef[STATE_SLOT].GetSelected());
	}
	
	if(ps3_input->ButtonPressed(0, PS3_BUTTON_L3) && ps3_input->ButtonDown(0, PS3_BUTTON_L1))
	{
		gambatte->saveState();
	}
		
	if(ps3_input->ButtonPressed(0, PS3_BUTTON_L3) && ps3_input->ButtonDown(0, PS3_BUTTON_R1))
	{
		gambatte->loadState();
	}
}

void						GambatteEmu::SaveState			()
{
	gambatte->saveState();
}

void						GambatteEmu::LoadState			()
{
	gambatte->loadState();
}

/*void						GambatteMenu::DoMenu			()
{
	NeedToDraw = true;
	Finished = false;

	while(!Finished)
	{
		if(WantToDie())
		{
			return;
		}
	
		ps3_input->Refresh();
		
		if(ps3_input->ButtonPressed(0, PS3_BUTTON_CIRCLE))
		{
			break;
		}
		
		uint32_t oldIndex = SettingIndex;
		SettingIndex -= ps3_input->ButtonPressed(0, PS3_BUTTON_UP) ? 1 : 0;
		SettingIndex += ps3_input->ButtonPressed(0, PS3_BUTTON_DOWN) ? 1 : 0;

		SettingIndex = SettingIndex < 0 ? SettingCount - 1 : SettingIndex;
		SettingIndex = SettingIndex >= SettingCount ? 0 : SettingIndex;
		NeedToDraw = oldIndex != SettingIndex ? true : NeedToDraw;
		
		if(NeedToDraw)
		{
			Draw();
			NeedToDraw = false;
		}
		
		Input();
		
		sys_timer_usleep(100 * 1000);
	}
	
	if(ChangeFilter == true)
	{
		Emulator->setVideoFilter(Filter);
		ChangeFilter = false;
	}
}*/

		
